/**
 * @class   wosh::FileSystem
 * @brief   CoreModule providing an high-level (and remote) access to local file-system.
 * 
 * \image html diagrams/FileSystem.png "wosh::FileSystem UML diagram"
 *
 * manage files and folders as URI?
 * examples:
 * @code
 *  :/FileSystem/
 * 
 * 		WOSH/var/extras/ ..			=> local installation folder (of current bin)
 * 		alias/my_track.mp3			=> alias mapping to another FS URI
 * 		local/$C/My Documents ..	=> local filesystem uri
 * 		shared/music/track1.mp3		=> dynamic mapping ! requires a lower level file-sharing system (such as SAMBA, NFS, ..)
 * 
 * @endcode
 *
 * @todo see brief;
 *       http://www.gnu.org/s/libc/manual/html_node/Simple-Directory-Lister.html
 *
 *
 *
 * @ingroup CoreModules
 ****************************************************************************
 * @version 0.6.030 $Id: FileSystem.h 2863 2010-08-07 04:28:58Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/*! \page page_core
 * \htmlonly <hr/> \endhtmlonly
 * \section page_core_filesystem FileSystem
 *
 * [..]
 *
 * \see wosh::FileSystem
 * \see wosh::FilePath
 * \see wosh::ResourcePath
 *
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR UserS;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Core_FileSystem_H__
 #define __WOSH_Core_FileSystem_H__

 #include <woshDefs.h>
 #include <core/WoshModule.h>
 #include <core/FilePath.h>
 #include <core/Containers.h>
 #include <core/Tree.h>
// #include <iostream>


namespace wosh {


class FileInfo : public ISerializable
 {
	WOSH_SERIALIZABLE(wosh::FileInfo)
	WOSH_COMPARE_RTTI(wosh::FileInfo)

	public:
		FileInfo()
			: type(0), time_created(0), time_modified(0), size(0) { }

		FileInfo( const FileInfo& m );
		virtual ~FileInfo() { }

	public:
		FileInfo& operator=(const FileInfo& m);
		bool operator==(const FileInfo &other) const;
		bool operator!=(const FileInfo &other) const { return !(*this == other);  }

/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const;
		virtual bool updateHash( DataHashContext* hash_context ) const;
//@}
	public:
		std::string local_path;	///< full path, os dependent
		std::string wosh_path;	///< path in wosh format
		short type;		///< 1=file; 2=dir; 3=link
		int64 time_created;
		int64 time_modified;
		int64 size;

}; // class def


 #define _FileSystem_NAME					"FileSystem"
 #define _FileSystem_URI					":FileSystem"

 #define _FileSystem_KEY_WoshRoot			"WoshRoot"
 #define _FileSystem_KEY_Aliases			"Aliases"
 #define _FileSystem_KEY_LocalFolderTemp	"LocalFolderTemp"
 #define _FileSystem_KEY_LocalFolderRoot	"LocalFolderRoot"

 #define _FileSystem_METHOD_file_delete		"file_delete"
 #define _FileSystem_METHOD_file_rename		"file_rename"
 #define _FileSystem_METHOD_file_size		"file_size"
 #define _FileSystem_METHOD_file_stat		"file_stat"

 #define _FileSystem_METHOD_dir_tree		"dir_tree"

 #define _FileSystem_METHOD_set_alias		"set_alias"
 #define _FileSystem_METHOD_rem_alias		"rem_alias"


class FileSystem : public WoshModule
 {
	WOSH_MODULE(wosh::FileSystem)

	typedef MapT<std::string, std::string> tStrStrMap;


	protected:
		/**
		 * @brief  Default constructor. Call base constructor and initialize some properties and hosted methods.
		 * @param parent [in] WoshKernel singleton, passed to WoshModule constructor
		 * @note   Called by WoshKernel only. Static getter (gamma singleton) will return NULL until kernel is created.
		 */
		FileSystem( const WoshKernel* parent = NULL );

		/**
		 * @brief  Call base class implementation, fix WOSH root folder and aliases
		 * @return result of WoshModule::onKernelInitializing()
		 */
		WRESULT onKernelInitializing();

		friend class wosh::WoshKernel;

	public:
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~FileSystem();


//@}
/** @name Public methods (not for bundles, usually hidden to most classes)
 * @{
 ******************************************************************************/
	public:
		WRESULT setWoshRoot(  const std::string& root_path );

		const std::string& getWoshRoot() const		{ return this->woshRootPath; }

		WRESULT registerAlias( const std::string& alias, const std::string& full_path );
		WRESULT unRegisterAlias( const std::string& alias );


//@}
/** @name FileSystem core methods
 * @{
 ******************************************************************************/
	public:

		static std::string getAlias( const std::string& alias );

		static bool resolveAlias( std::string& path_step );
		static bool resolveLocalPath( const std::string& local_path, std::string& wosh_path );


		static WRESULT reserveTempFile( std::string& filename, const std::string& filename_tip = "gtmp" );

		static WRESULT freeTempFile( const std::string& full_wosh_path );

		static std::string getCurrentWorkingDirectory();

//@}
/** @name Static filesystem methods
 * @{
 ******************************************************************************/
	public:
		/**
		 * @brief  Delete a file, similar to POSIX command \c rm or Window's \c del.
		 * @param filepath [in] the full (local) path of the file to be removed
		 * @return WRET_OK when the file was successfully deleted; a custom error code else
		 */
		static WRESULT deleteFile( const std::string& filepath );
		/**
		 * @brief  Rename (move) a file, similar to POSIX command \c mv.
		 * @param filepath [in] the full (local) path of the file to be evaluated
		 * @param new_filepath [in] the new full (local) path of the file
		 * @return WRET_OK when the file was successfully renamed (moved); a custom error code else
		 */
		static WRESULT renameFile( const std::string& filepath, const std::string& new_filepath );
		/**
		 * @brief  Get the selected timestamp field of a file, epoch format (seconds from 1970).
		 * @param filepath [in] the full (local) path of the file to be evaluated
		 * @param field [in] select the field to be retrieved: 0=LastModifiedTime; 1=CreationTime; 2=LastAccessTime
		 * @return timestamp in epoch format (seconds from 1970); 0 on errors
		 */
		static int64 getTimeStampOf( const std::string& filepath, short field = 0 );
		/**
		 * @brief  Get the size a file in bytes.
		 * @param filepath [in] the full (local) path of the file to be evaluated
		 * @return size in bytes; 0 on errors
		 */
		static int64 getSizeOf( const std::string& filepath );

		static short getTypeOf( const std::string& filepath );

		static WRESULT getFileInfo( FileInfo& info, const std::string& filepath );


		/**
		 * @brief  Save a block of data to file.
		 * @param filepath [in] the full (local) path of the file to be written
		 * @param data [in] pointer of the data-block to be written
		 * @param size [in] the size of the data to be written
		 * @param append [in] when true it will open the file for appending, else content is erased
		 * @return WRET_ERR_PARAM if data/size is invalid; WRET_ERR_ILLEGAL_USE if file can't be opened; WRET_OK on success
		 */
		static WRESULT saveTextAs( const std::string& filepath, const char* data, int64 size, bool append = false );

		static WRESULT getFilesOf( const std::string& dir, std::vector<std::string>& files, bool recursive = false, bool full_path = false, const std::string& pattern = "" );


		static WRESULT getDirNodeOf( TreeNode* dirNode, const std::string& dir, int recursive_level = 1, const std::string& pattern = "" );

		static Tree* getTreeOf( const std::string& dir, int recursive_level = 1, const std::string& pattern = "" );

//@}
/** @name Internal Mehods and Events management
 * @{
 ******************************************************************************/
	private:
		/**
		 * @brief  Access the FileSystem singleton. Gamma Pattern.
		 *         Static reference is allocated and detroyed by WoshKernel on constructor/destructor respectively
		 * @return pointer to FileSystem singleton. May be NULL (if kernel has not been allocated yet)
		 */
		static FileSystem* getInstance();

//@}
	private:
		Response* mmDoListAliases( const Request* request );
		Response* mmDoSetAlias( const Request* request );
		Response* mmDoRemoveAlias( const Request* request );

		Response* mmDoFileDelete( const Request* request );
		Response* mmDoFileRename( const Request* request );
		Response* mmDoFileSize( const Request* request );
		Response* mmDoFileStat( const Request* request );

		Response* mmDoDirTree( const Request* request );

	private:
		std::string woshRootPath;		///< root path of WOSH FileSystem (containing bin, etc, var, ..)
		static tStrStrMap fsAliases;	///< alias->full local path


}; // class def

}; // namespace wosh

#endif //__WOSH_Core_FileSystem_H__
